package com.mlk.good.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.google.common.collect.Maps;
import com.mlk.constant.EngConstant;
import com.mlk.core.component.page.Page;
import com.mlk.core.component.page.Pager;
import com.mlk.core.exception.GlobalException;
import com.mlk.core.util.ServerResponse;
import com.mlk.engSystem.constant.SystemParam;
import com.mlk.engSystem.service.EngSysParamService;
import com.mlk.engUser.mapper.EngUserMapper;
import com.mlk.engUser.po.EngUser;
import com.mlk.good.lib.SybPayService;
import com.mlk.good.mapper.*;
import com.mlk.good.po.EngGood;
import com.mlk.good.po.EngGoodInfo;
import com.mlk.good.po.EngGoodOrder;
import com.mlk.good.po.EngGoodPic;
import com.mlk.good.service.EngGoodOrderService;
import com.mlk.good.vo.EngGoodOrderVO;
import com.mlk.score.mapper.EngInScoreMapper;
import com.mlk.score.mapper.EngOutScoreMapper;
import com.mlk.score.po.EngInScore;
import com.mlk.score.po.EngOutScore;
import com.mlk.wx.WxPayProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantLock;

@Service
@Slf4j
public class EngGoodOrderServiceImpl implements EngGoodOrderService {

    @Resource
    private EngGoodOrderMapper engGoodOrderMapper;

    @Resource
    private EngGoodInfoMapper engGoodInfoMapper;

    @Resource
    private EngGoodIntroduceMapper engGoodIntroduceMapper;

    @Resource
    private EngGoodPicMapper engGoodPicMapper;

    @Resource
    private EngUserMapper engUserMapper;

    @Resource
    private EngSysParamService engSysParamService;

    @Resource
    private EngGoodMapper engGoodMapper;

    @Resource
    private EngInScoreMapper engInScoreMapper;

    @Resource
    private EngOutScoreMapper engOutScoreMapper;

    /**
     * 初始化订单
     * @param order
     * @return
     */
    @Override
    public ServerResponse initOrder(EngGoodOrder order) {

        EngGoodOrderVO vo = new EngGoodOrderVO();
        BeanUtils.copyProperties(order,vo);
        ServerResponse response = this.calculateOrderPrice(vo);
        if (!response.isSuccess()){
            throw new GlobalException(response.getMsg());
        }
        vo = (EngGoodOrderVO) response.getData();
        BeanUtils.copyProperties(vo,order);
        // 补充必要的属性内容
        order.setCreateTime(new Date());
        order.setGoodName(vo.getGoodName());
        order.setKeyword(vo.getKeyword());
        order.setOrderCode(String.valueOf(IdUtil.createSnowflake(2L,2L).nextId()));
        int  count =  this.engGoodOrderMapper.insert(order);
        if(count == 0){
            throw new GlobalException("操作失败");
        }

        return ServerResponse.ok("操作成功");
    }

    /**
     * 取消订单
     * @param orderCode
     * @return
     */
    @Override
    public ServerResponse cancelOrder(String orderCode) {
       int count =  this.engGoodOrderMapper.updateOrderStatus(orderCode, EngConstant.GOODORDER_STATUS.CANCEL_STATUS);
       if(count == 0){
           throw new GlobalException("取消失败");
       }
        return ServerResponse.ok("取消成功");
    }

    @Transactional
    @Override
    public ServerResponse calculateOrderPrice(EngGoodOrderVO vo) {
        // 获取下单人的信息
        EngUser user = this.engUserMapper.selectOne(EngUser.builder().openId(vo.getOpenId()).build());
        // 获取商品的信息(参数和规格)
        if(vo.getParamId() == null){
            throw new GlobalException("参数规格不能为空！");
        }
        EngGoodInfo goodInfo = this.engGoodInfoMapper.selectById(vo.getParamId());

        // 获取积分兑换的比例
        BigDecimal rate = this.engSysParamService.getBigDecimalValue(SystemParam.SCORE_TO_MONEY_RATE);


        // 判断用户是否有积分可以换购
        BigDecimal requiredMinScore = new BigDecimal(vo.getNum()).multiply(goodInfo.getPrice()).multiply(goodInfo.getMinRate()).divide(rate);
        if(user.getScore().doubleValue() < requiredMinScore.doubleValue()){
            throw new GlobalException("您的积分不足以购买该商品,请减少数量或选择其他商品");
        }

        // 现在用户有资格买商品
        BigDecimal requiredMaxScore = new BigDecimal(vo.getNum()).multiply(goodInfo.getPrice()).multiply(goodInfo.getMaxRate()).divide(rate);


        EngGoodOrderVO retVo = new EngGoodOrderVO();

        // 现在表示可以使用全部的积分比例
        if(user.getScore().doubleValue() >= requiredMaxScore.doubleValue()){
            // 说明积分可以完全抵现
            // 需要的积分
            BigDecimal score = requiredMaxScore;
            BigDecimal savePrice = score.multiply(rate);
            BigDecimal price = goodInfo.getPrice().multiply(new BigDecimal(vo.getNum())).subtract(savePrice);
            retVo.setNum(vo.getNum());
            retVo.setTotalPrice(price);
            retVo.setCostScore(score.intValue());
        }else{
            // 部分抵现
            // 部分抵现
            BigDecimal score = new BigDecimal(user.getScore());
            BigDecimal savePrice = score.multiply(rate);
            BigDecimal price = goodInfo.getPrice().multiply(new BigDecimal(vo.getNum())).subtract(savePrice);
            retVo.setNum(vo.getNum());
            retVo.setTotalPrice(price);
            retVo.setCostScore(score.intValue());
        }

        retVo.setGoodId(vo.getGoodId());
        EngGood engGood = this.engGoodMapper.selectOne(EngGood.builder().id(vo.getGoodId()).build());
        retVo.setGoodName(engGood.getName());
        retVo.setBranch(engGood.getBranch());
        retVo.setParamId(vo.getParamId());
        retVo.setParamName(goodInfo.getParam());
        retVo.setSinglePrice(goodInfo.getPrice());


        // 查询图片信息
        List<EngGoodPic> picList = this.engGoodPicMapper.selectList(new EntityWrapper<>(EngGoodPic.builder().goodId(vo.getGoodId()).build()));
        if(!picList.isEmpty()){
            retVo.setGoodPicUrl(picList.get(0).getPicUrl());
        }

        // 查询运费信息
        BigDecimal sendFee = this.engSysParamService.getBigDecimalValue(SystemParam.SEND_FEE);
        retVo.setSendPrice(sendFee);
        // 重新计算总价
        retVo.setTotalPrice(retVo.getTotalPrice().add(retVo.getSendPrice()));
        // 补充其他的属性,方便前台的使用
        retVo.setKeyword(engGood.getKeyword());
        retVo.setRate(rate);
        retVo.setOpenId(vo.getOpenId());
        retVo.setAddress(vo.getAddress());
        return ServerResponse.ok(retVo);

    }

    /**
     * 查询订单的状态信息
     * @param openId
     * @param status
     * @return
     */
    @Override
    public ServerResponse queryOrder(String openId, Integer status) {
        EngGoodOrderVO vo = new EngGoodOrderVO();
        vo.setOpenId(openId);
        vo.setStatus(status);
        return ServerResponse.ok(this.engGoodOrderMapper.selectForPage(vo));
    }

    /**
     * 分页查询参数
     * @param vo
     * @return
     */
    @Override
    @Page
    public Pager listPage(EngGoodOrderVO vo) {
        return Pager.adapt(this.engGoodOrderMapper.selectForPage(vo));
    }

    /**
     * 订单预支付--- 核心的方法
     * @param openId
     * @param orderCode
     * @return
     */
    @Override
    @Transactional
    public ServerResponse prePayCheck(String openId, String orderCode) {
        EngUser user = this.engUserMapper.selectOne(EngUser.builder().openId(openId).build());
        EngGoodOrder order = this.engGoodOrderMapper.selectOne(EngGoodOrder.builder().orderCode(orderCode).build());

        // 判断用于是否有足够的积分
        if (user.getScore().doubleValue() < order.getCostScore().doubleValue()){
            return ServerResponse.fail("当前用户的积分不足,需要"+order.getCostScore().doubleValue()+"积分,现有"+user.getScore().doubleValue()+"积分");
        }

        // 判断是否需要掉支付接口
        Map<String,Boolean> maps = Maps.newHashMap();
        if(order.getTotalPrice().doubleValue() == 0.0d){
            maps.put("needPay",false);
        }else{
            maps.put("needPay",true);
        }
        return ServerResponse.ok("用户可以支付");
    }

    /**
     * 查询订单详情
     * @param orderCode
     * @return
     */
    @Override
    public ServerResponse getOrderDetail(String orderCode) {
        EngGoodOrder order = this.engGoodOrderMapper.selectOne(EngGoodOrder.builder().orderCode(orderCode).build());
        return ServerResponse.ok("查询成功",order);
    }

    /**
     * 查询已经完成的订单
     * @param openId
     * @return
     */
    @Override
    @Page
    public Pager queryFinishedOrder(String openId) {
        EngGoodOrderVO vo = new EngGoodOrderVO();
        vo.setOpenId(openId);
        vo.setQueryStatus(" in (5,6) ");
        return Pager.adapt(this.engGoodOrderMapper.selectForPage(vo));
    }

    /**
     * 客户确认订单
     * @param orderCode
     * @return
     */
    @Override
    @Transactional
    public ServerResponse customConfirmOrder(String orderCode) {
        EngGoodOrder order = this.engGoodOrderMapper.selectOne(EngGoodOrder.builder().orderCode(orderCode).build());
        // 进行数据的处理

        BigDecimal rate = this.engSysParamService.getBigDecimalValue(SystemParam.SCORE_OF_BUY_GOOD);
        // 给用户增加积分
        int score = rate.multiply(order.getTotalPrice()).intValue();
        int count = 0;
        if(score > 0){
            count = this.engUserMapper.addUserScore(order.getOpenId(),(-1)*score);
            if(count == 0){
                throw new GlobalException("操作失败");
            }

            // 增加积分in的记录
            EngInScore inScore = new EngInScore();
            inScore.setOpenId(order.getOpenId());
            inScore.setCreateTime(new Date());
            inScore.setNum(score);
            inScore.setType(EngConstant.IN_SCORE_SOURCE.BUY_SCORE);
            count = this.engInScoreMapper.insert(inScore);
            if(count == 0){
                throw new GlobalException("操作失败");
            }
        }

        
        // 修改订单的状态
        count = this.engGoodOrderMapper.updateOrderStatus(orderCode,EngConstant.GOODORDER_STATUS.FINISHED_STATUS);
        if(count == 0){
            throw new GlobalException("操作失败");
        }

        return ServerResponse.ok("操作成功");
    }

    /**
     * 用户接单
     * @param orderCode
     * @return
     */
    @Override
    @Transactional
    public ServerResponse accept(String orderCode) {
        int count = this.engGoodOrderMapper.updateOrderStatus(orderCode,EngConstant.GOODORDER_STATUS.PICKED_STATUS);
        if(count == 0){
            throw new GlobalException("接单失败");
        }
        return ServerResponse.ok("接单成功");
    }

    /**
     * 订单发货
     * @param orderCode
     * @return
     */
    @Transactional
    @Override
    public ServerResponse send(String orderCode) {
       int count =  this.engGoodOrderMapper.updateOrderStatus(orderCode,EngConstant.GOODORDER_STATUS.SENDED_STATUS);
       if(count == 0){
           throw new GlobalException("发货成功");
       }
        return ServerResponse.ok("发货成功");
    }

    @Resource
    private WxPayProperties properties;

    @Value("${nengyuanbao.domain}")
    private String domain;

    final private ReentrantLock lock  = new ReentrantLock();

    @Override
    @Transactional
    public ServerResponse payOrder(String orderCode) {

        // 获取订单的信息
        EngGoodOrder order = this.engGoodOrderMapper.selectOne(EngGoodOrder.builder().orderCode(orderCode).build());
        if(order.getStatus() != EngConstant.GOODORDER_STATUS.INIT_STATUS){
            ServerResponse.ok("统一下单成功");
        }

//        // 组装统一下单接口
//        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
//        // 设置信息
//        request.setAppid(properties.getAppId());
//        request.setTradeType("JSAPI");
//        request.setSpbillCreateIp(IPUtils.getInstance().getIpAddr());
//        request.setMchId(properties.getMchId());
//        request.setOpenid(order.getOpenId());
//        request.setOutTradeNo(orderCode);
//        request.setBody("能源宝商城积分换购");
//        // 测试模拟的数据
//        request.setTotalFee(30);
//        // 真实环境下的值
//        //request.setTotalFee(order.getTotalPrice().multiply(new BigDecimal(100d)).intValue());
//        // 设置回调的接口内容
//        request.setNotifyUrl(domain+"/api/engGood/order/notify/order");
//        Object result = null;
//        try {
//            result = SpringUtils.getBean(WxPayService.class).createOrder(request);
//        } catch (WxPayException e) {
//           log.error("微信支付出现问题,",e);
//           return ServerResponse.fail("统一下单出现错误");
//        }
//
//        return ServerResponse.ok("统一下单成功",result);

        SybPayService service = new SybPayService();
        // 订单号 ///
        Map<String, String> map = null;
        try {
            map = service.pay(1, orderCode, "W06", "能源宝支付", "能源宝支付", order.getOpenId(), "", domain+"/api/engGood/order/notify/order", "", "", "", "");
        } catch (Exception e) {
            log.error("微信支付出现问题",e);
        }
        System.out.println("-----------------");
        System.out.println(map);
        return ServerResponse.ok(map);
    }

    /**
     * 此接口会被微信回调,因此需要做幂等性操作.
     * 此处的实现会使该方法被强制加锁,效率极低.
     */
    @Override
    public String handleWxPayOrderNotifyResult(TreeMap<String,String> params) {
        String orderCode = params.get("outtrxid");
        EngGoodOrder order = this.engGoodOrderMapper.selectOne(EngGoodOrder.builder().orderCode(orderCode).build());
        try{
            lock.lock();
            if(order.getStatus() != EngConstant.GOODORDER_STATUS.INIT_STATUS){
                WxPayNotifyResponse.success("支付成功");
            }
            // 确定该订单被支付了
            if(order.getTotalPrice().doubleValue() == 0){
                // 直接修改订单的状态就可以了
                this.engGoodOrderMapper.updateOrderStatus(orderCode,EngConstant.GOODORDER_STATUS.PAYED_STATUS);
            }
            // 下面需要给用户减去积分
            this.engUserMapper.addUserScore(order.getOpenId(),(-1)*order.getCostScore());
            // 添加积分支出明细
            EngOutScore engOutScore = new EngOutScore();
            engOutScore.setOpenId(order.getOpenId());
            engOutScore.setCreateTime(new Date());
            engOutScore.setNum(order.getCostScore());
            engOutScore.setType(EngConstant.OUT_SCORE_TARGET.BUY_SCORE);
            this.engOutScoreMapper.insert(engOutScore);

            // 我们只需要修改订单的状态就好了
            this.engGoodOrderMapper.updateOrderStatus(orderCode,EngConstant.GOODORDER_STATUS.PAYED_STATUS);

            return WxPayNotifyResponse.success("支付成功");
        }finally {
            lock.unlock();
        }

    }
}
